package ca.cbc.mediacms.service;

import ca.cbc.mediacms.persistence.CategoryPersistence;
import ca.cbc.medialib.entity.Category;
import ca.cbc.medialib.entity.Media;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Arash Bizhanzadeh <arash.bizhan-zadeh@cbc.ca>
 *         Date: 18/02/11
 *         Time: 3:50 PM
 *         Copyrighted to CBC. All rights reserved.
 */

@Path("/r/category/")
public class CategoryService {
    private static Logger logger = LoggerFactory.getLogger(CategoryService.class);
    private CategoryPersistence categoryPersistence;
     
    public CategoryPersistence getCategoryPersistence() {
		return categoryPersistence;
	}

	public void setCategoryPersistence(CategoryPersistence categoryPersistence) {
		this.categoryPersistence = categoryPersistence;
	}

	/**
     * This function deal with combine possible category with two fullTitle
     * @param fullTitle
     * @return
     */
    protected Category combineChildrenCategories(String fullTitle) {
        Category cat = categoryPersistence.findByFullTitle(fullTitle);
        Category subCat = null;
        String unStripedFullTitle = this.unStripFullTitle(fullTitle);
        if(!fullTitle.endsWith(unStripedFullTitle)) {
        	subCat = categoryPersistence.findByFullTitle(unStripedFullTitle);
        }
        
        if(cat == null && subCat == null){
        	throw new WebApplicationException(404);
        } else if(cat == null && subCat != null) {
        	cat = subCat;
        } else if(cat != null && subCat != null) {        
        	cat.removeChild(subCat);
        	for(Category c : subCat.getChildren()) {
        		if(!cat.getChildren().contains(c)) {
        			cat.getChildren().add(c);
        		}
        	}
        }
        return cat;
    }

    /**
     * This function deal with combine possible category with two fullTitle
     * @param fullTitle
     * @return
     */
    protected Category combineChildrenMedias(String fullTitle) {
        Category cat = categoryPersistence.findByFullTitle(fullTitle);
        Category subCat = null;
        String unStripedFullTitle = this.unStripFullTitle(fullTitle);
        if(!fullTitle.endsWith(unStripedFullTitle)) {
        	subCat = categoryPersistence.findByFullTitle(unStripedFullTitle);
        }     
        
        if(cat == null && subCat == null){
        	throw new WebApplicationException(404);
        } else if(cat == null && subCat != null) {
        	cat = subCat;
        } else if(cat != null && subCat != null) {            
            for(Media m : subCat.getMedias()) {
            	if(!cat.getMedias().contains(m)) {
            		cat.getMedias().add(m);
            	}
            }
        }
        
        for(Media media : cat.getMedias()) {
        	this.emptyDuplicatedCategoryFullTitle(media);
        }
        
        return cat;
    }

	private <T> void dispatchToFreemarker(T entity, String template, HttpServletRequest request, HttpServletResponse response){
        try{
            response.setContentType("application/xml");
            request.setAttribute("entity",entity);
            request.getRequestDispatcher(template).forward(request,response);
        } catch (ServletException e) {
            logger.error("Error in distpaching the request " + template,e);
            throw new WebApplicationException(500);
        } catch (IOException e) {
            logger.error("Error in distpaching the request " + template, e);
            throw new WebApplicationException(500);

        }
    }

    @GET
    @Path("/medias")
    @Produces("application/xml")
    @Transactional(readOnly=true)
    public void getCategoryByFullTitle(@Context HttpServletRequest request,
                                       @Context HttpServletResponse response,
                                       @QueryParam("fullTitle") String fullTitle){        
        dispatchToFreemarker(combineChildrenMedias(fullTitle),"/medias.ftl",request,response);
    }

    @GET
    @Path("{id}/medias")
    @Produces("application/xml")
    @Transactional(readOnly=true)
    public void getCategoryMedias(@Context HttpServletResponse response,
        @Context HttpServletRequest request,@PathParam("id") long id){
        try{
            Category cat=  categoryPersistence.findById(id);
            if(cat == null){
                throw new WebApplicationException(404);
            }
            dispatchToFreemarker(cat,"/medias.ftl",request,response);
        } catch (Exception e) {
            throw new WebApplicationException(500);
        }

    }
    
    @GET
    @Path("{id}/children")
    @Produces("application/xml")
    @Transactional(readOnly=true)
    public void getCategoryChildren(@Context HttpServletRequest request,
                                    @Context HttpServletResponse response,
                                    @PathParam("id") long id) {

    	Category cat = categoryPersistence.findById(id);
    	if (cat == null) {
    		System.out.println("category is null");
          	throw new WebApplicationException(404);
     	}
        dispatchToFreemarker(cat,"/childCategories.ftl",request,response);
    }

    @GET
    @Path("children")
    @Produces("application/xml")
    @Transactional(readOnly=true)
    public void getCategoryChildrenWithFullTitle(@Context HttpServletRequest request,
                                                 @Context HttpServletResponse response,
                                                 @QueryParam ("fullTitle") String fullTitle){
        dispatchToFreemarker(combineChildrenCategories(fullTitle),"/childCategories.ftl",request,response);
    }
    
    /**
     * This method will set duplicated category fullname to empty
     * @param media
     */
    protected void emptyDuplicatedCategoryFullTitle(Media media) {
    	Set<String> fullTitles = new HashSet<String>();

    	for(Category category : media.getCategories()) {
    		String fullTitle = stripFullTitle(category.getFullTitle());
    		if(fullTitles.contains(fullTitle)) {
    			category.setFullTitle("");
    		} else {
    			category.setFullTitle(fullTitle);
    			fullTitles.add(fullTitle);
    		}
    	}
    }
    
    /**
     * This function strip "Shows/Shows/ABC" to "Shows/ABC"
     * @param fullTitle
     * @return
     */
    protected String stripFullTitle(String fullTitle) {
    	String str = fullTitle;
    	if(fullTitle.startsWith("Shows/Shows")) {
    		str =  fullTitle.replaceFirst("Shows/Shows", "Shows");
    	} else if (fullTitle.startsWith("Radio/Shows")) {
    		str =  fullTitle.replaceFirst("Radio/Shows", "Radio");
    	}
    	return str;
    }
    
    /**
     * This function unStrip "Shows/ABC" to "Shows/Shows/ABC"
     * @param fullTitle
     * @return
     */
    protected String unStripFullTitle(String fullTitle) {
    	String str = fullTitle;
    	if(fullTitle.startsWith("Shows")) {
    		str =  fullTitle.replaceFirst("Shows", "Shows/Shows");
    	} else if (fullTitle.startsWith("Radio")) {
    		str =  fullTitle.replaceFirst("Radio", "Radio/Shows");
    	}	
    	return str;
    }
}
